Clojure Cheat Sheet

This cheat sheet provides a concise overview of core Clojure concepts and syntax.

1. Syntax Basics

  • S-expressions: Code is written using nested lists enclosed in parentheses (...).
  • Prefix Notation: The first element in a list is the function/macro/operator, followed by arguments: (+ 1 2) => 3.
  • Comments: Start with ; for single-line comments. (comment ...) macro for multi-line comments (forms inside must be valid). #_ reader macro ignores the next form.

2. Data Types

  • Numbers:
    • Integers: 1, -10, 10N (BigInt)
    • Floating-point: 1.0, 3.14, 1.5M (BigDecimal)
    • Ratios: 22/7 (automatically simplified, e.g., 2/4 becomes 1/2)
    • Hex: 0xff => 255
    • Octal: 077 => 63
    • Radix: 2r1101 => 13, 16rFF => 255
  • Strings: "Hello", "Multiline\nString". Java String.
  • Characters: \c, \newline, \space, \u0041 (Unicode). Java Character.
  • Booleans: true, false. Only false and nil are logically false. Everything else is logically true.
  • nil: Represents nothing or absence of value. Logically false.
  • Keywords: Start with a colon, evaluate to themselves. Often used as map keys. :a, :my-keyword, ::qualified/keyword.
  • Symbols: Names used to refer to vars (functions, values), locals, Java classes. +, my-var, String. Use ' (quote) to prevent evaluation: 'my-symbol.

3. Collections (Immutable & Persistent)

  • Lists: '(1 2 3), (list 1 2 3). Ordered, efficient addition to the front. Use ' to create literal lists.
  • Vectors: [1 2 3], (vector 1 2 3). Ordered, indexed, efficient random access and addition to the end.
  • Maps: {:a 1 :b 2}, (hash-map :a 1 :b 2). Unordered key-value pairs. Keys are often keywords.
    • sorted-map: Keys sorted by compare.
  • Sets: #{1 2 3}, (hash-set 1 2 3). Unordered collection of unique values.
    • sorted-set: Elements sorted by compare.

Common Collection Functions:

  • (first coll): Get the first item.
  • (rest coll): Get a sequence of all items except the first. Returns () for empty/single-item seq.
  • (next coll): Get sequence of items after first. Returns nil if no more items. (seq (rest coll))
  • (cons item coll): Add item to the front (logical) of a collection. Returns a seq.
  • (conj coll item & items): Add item(s) to a collection in the most efficient way (front for lists, end for vectors). Returns the same collection type.
  • (get coll key [not-found]): Get value for key. Works on maps, sets, vectors. Returns nil or not-found if key missing.
  • (get-in coll [key1 key2 ...]): Access nested value.
  • (assoc coll key val & kvs): Add/update key-value pairs in a map or vector index.
  • (assoc-in coll [k1 k2 ...] val): Update nested value.
  • (dissoc map key & keys): Remove keys from a map.
  • (update coll key f & args): Apply function f to the value at key.
  • (update-in coll [k1 k2 ...] f & args): Update nested value using function f.
  • (count coll): Get the number of items.
  • (seq coll): Get a sequence view of the collection. Returns nil if empty.
  • (empty? coll): Check if collection is empty.
  • (map f coll & colls): Apply function f to each item. Lazy.
  • (filter pred coll): Keep items where (pred item) is true. Lazy.
  • (remove pred coll): Remove items where (pred item) is true. Lazy.
  • (reduce f coll) / (reduce f val coll): Reduce collection using function f.
  • (take n coll): Get first n items. Lazy.
  • (drop n coll): Drop first n items. Lazy.
  • (nth coll index [not-found]): Get item at index (0-based). Throws error if out of bounds unless not-found is provided.
  • (contains? coll key): Check if a key (or index for vector, element for set) exists.

4. Control Flow

  • (if test then else?): Standard if/else. else is optional (defaults to nil).
  • (when test & body): Executes body if test is true. Implicit do.
  • (when-not test & body): Executes body if test is false. Implicit do.
  • (cond & clauses): Takes test/expr pairs. Evaluates first expr whose test is true. :else for default. (cond test1 expr1 test2 expr2 :else expr-else)
  • (case expr & clauses): Matches expr against literal constants. (case x 1 "one" 2 "two" "other")
  • (do & exprs): Evaluates expressions sequentially, returns the last. Used for side effects.
  • (loop [binding1 init1 ...] & body): Establishes loop bindings. Use recur to jump back to the loop point with new binding values.
  • (recur & exprs): Rebinds enclosing loop or function parameters and jumps to the start. Must be in tail position.
  • (try body* (catch ClassName name expr*)* (finally expr*)?): Exception handling.

5. Functions

  • (defn name doc-string? attr-map? [params*] prepost-map? body): Define a named function.
  • (defn name ... ([params1*] body1) ([params2*] body2) ...): Define function with multiple arities.
  • (fn name? [params*] body): Define an anonymous function.
  • #(...): Reader macro for anonymous function. Args: %, %1, %2, etc. Rest args: %&. #(+ %1 %2)
  • [arg1 arg2 & rest]: Variadic function arguments. rest is a seq of remaining args.
  • {:keys [a b] :or {a default-a}}: Destructuring map arguments with defaults.

6. Vars and Bindings

  • (def symbol init?): Defines a global Var in the current namespace.
  • (let [binding1 init1 ...] body): Creates lexical bindings (locals). Bindings are immutable.
  • Destructuring: Binding parts of collections within let, fn, loop.
    • Sequential: [a b & rest] = [1 2 3 4] => a=1, b=2, rest=(3 4)
    • Map: {:keys [x y] :as all} = {:x 1 :y 2 :z 3} => x=1, y=2, all={:x 1 :y 2 :z 3}

7. State & Concurrency

  • Immutability: Core data structures (lists, vectors, maps, sets) are immutable. Functions typically return new values instead of modifying originals.
  • Atoms: (atom initial-val). For uncoordinated, synchronous updates. Use swap! (swap! atom-name f & args) and reset! (reset! atom-name new-val). Get value with @ or deref.
  • Refs: (ref initial-val). For coordinated, synchronous updates within transactions. Use dosync and alter (alter ref-name f & args) or commute. Get value with @ or deref.
  • Agents: (agent initial-val). For uncoordinated, asynchronous updates. Use send (send agent-name f & args) or send-off. Get value with @ or deref.

8. Namespaces

  • (ns name & options): Set the current namespace, optionally requiring/using/importing.
  • (:require [namespace :as alias :refer [var1 var2]] ...): Load namespace, create alias, refer specific vars.
  • (:use [namespace :only [var1]] ...): Load and refer vars (often discouraged in favor of :require :refer).
  • (:import [package.Class1 package.Class2] ...): Import Java classes.
  • my-namespace/my-var: Accessing a var in another namespace.
  • alias/my-var: Accessing via alias.

9. Java Interop

  • (new ClassName arg1 ...) or (ClassName. arg1 ...): Create Java object.
  • (.instanceMember instance arg1 ...): Call instance method or access field. (.toUpperCase "hello")
  • (Class/staticMember arg1 ...): Call static method or access field. (Math/pow 2 10)
  • (.-instanceField instance): Access instance field specifically.
  • (set! (.field instance) val): Set instance field.
  • (doto instance (method1 ...) (method2 ...)): Call multiple methods on the same instance, returns instance.
  • (proxy [Superclass Interface1 ...] [constructor-args] {methods}): Create proxy object.
  • (reify Interface1 ... {methods}): Create anonymous object implementing interfaces/protocols.

10. Macros

  • (defmacro name [params*] body): Define a macro. Code in body runs at compile time to generate code.
  • ` (Syntax Quote): Template code generation.
  • ~ (Unquote): Evaluate expression inside syntax quote.
  • ~@ (Unquote Splicing): Splice a sequence into the surrounding list inside syntax quote.

11. Laziness

  • Many sequence functions (map, filter, range, iterate, etc.) are lazy, computing items only when needed.
  • (lazy-seq body): Macro to create lazy sequences explicitly.
  • (doall coll) / (dorun coll): Force evaluation of a lazy sequence. dorun doesn't hold the head.
  • (realized? coll): Check if a lazy sequence has been realized.